const os = require('os');
const { exec, spawn } = require('child_process');

class PythonEnvManager {
    constructor() {}

    // 调用exec执行python脚本
    async runCommand(envName, command) {
        return new Promise((resolve, reject) => {
            const commandEnv = envName == 'local' || !envName ? command : `conda run -n ${envName} ${command}`;

            exec(commandEnv, { shell: true }, (error, stdout, stderr) => {
                if (error) {
                    reject(error);
                } else if (stderr && !stdout) {
                    // 如果有stderr而没有stdout，也认为是错误
                    reject(new Error(stderr));
                } else {
                    // console.log(stdout.toString());
                    resolve(stdout.trim());
                }
            });
        });
    }

    // 调用spawn执行python脚本
    async runCommandEx(envName, command, args = [], setProcess) {
        console.log(`envName = ${envName}, command = ${command}, args = `, args);

        return new Promise((resolve, reject) => {
            let commandArr = [];
            if (envName === 'local' || !envName) {
                commandArr = [command, '-u', ...args];
            } else {
                commandArr = ['conda', 'run', '-n', envName, command, ...args];
                // commandArr = ['conda', 'run', '-n', envName, '--live-stream', command, '-u', ...args];
            }

            const proc = spawn(commandArr[0], commandArr.slice(1), {
                shell: true,
                stdio: 'pipe'
            });

            // 将子进程实例传递给任务队列，方便在任务队列中，直接关闭该任务执行
            setProcess(proc);

            let output = '';
            proc.stdout.on('data', (data) => {
                // console.log(data.toString().trim());
                output += data.toString();
            });

            proc.stderr.on('data', (data) => {
                console.error(data.toString());
                reject({ code: -1, msg: data.toString() });
            });

            proc.on('close', (code) => {
                if (code === 0) {
                    resolve({ code: code, msg: output.trim() });
                } else {
                    console.log(`子进程退出，退出码 ${code}`);
                    reject({ code: code, msg: '子进程退出' });
                }
            });
        });
    }

    async getPythonVersion(command) {
        try {
            const stdout = await this.runCommand(null, `${command} --version`);
            // console.log(`stdout = `, stdout);
            return stdout;
        } catch (err) {
            // console.error(err);
        }
    }

    async getEnvList() {
        try {
            // 获取 conda 环境列表及版本信息
            const envListResult = await this.runCommand(null, 'conda env list --json');
            const envs = JSON.parse(envListResult)['envs'];
            const condaEnvs = [];

            for (const envPath of envs) {
                const nameMatch = /envs\/([^\/]+)$/.exec(envPath);
                const name = nameMatch ? nameMatch[1] : 'base'; // If no env folder found, consider it to be 'base'

                let version = 'Unknown';
                try {
                    const pythonPath = os.platform() === 'win32' ? `${envPath}\\python.exe` : `"${envPath}/bin/python"`;
                    const versionResult = await this.runCommand(null, `${pythonPath} --version`);
                    version = versionResult.match(/Python (\S+)/i)[1]; // Match version number
                } catch (versionError) {
                    // Handle error (version remains 'Unknown')
                }
                condaEnvs.push({ name, path: envPath, version });
            }

            // 检查本地环境python命令
            // 清除可能影响结果的conda环境路径
            const originalPath = process.env.PATH;
            try {
                const condaPath = process.env.CONDA_PREFIX ? `${process.env.CONDA_PREFIX}/bin` : '';
                if (condaPath) {
                    process.env.PATH = process.env.PATH.split(':')
                        .filter((p) => !p.startsWith(condaPath))
                        .join(':');
                }
                // console.log(condaPath);

                let nativeEnvs = [];
                for (const cmd of ['python', 'python3']) {
                    try {
                        const versionOutput = await this.getPythonVersion(cmd);
                        const versionMatch = versionOutput.match(/Python (\S+)/);
                        const version = versionMatch ? versionMatch[1] : 'Unknown';

                        const pathCommand = os.platform() === 'win32' ? 'where' : 'which';
                        const pathOutput = await this.runCommand(null, `${pathCommand} ${cmd}`);
                        const paths = pathOutput.split(os.EOL).filter(Boolean);

                        paths.forEach((path) => {
                            nativeEnvs.push({ name: cmd, path, version });
                        });
                    } catch (e) {
                        console.error(`无法获取${cmd}的环境信息`);
                    }
                }

                return { conda: condaEnvs, native: nativeEnvs };
            } finally {
                process.env.PATH = originalPath;
            }
        } catch (err) {
            throw err;
        }
    }
}

module.exports = { PythonEnvManager };
